
package com.kevin.demo.dao.base;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.kevin.demo.dao.IDao;
import com.kevin.demo.framwork.MyMapper;
import com.kevin.demo.utils.ReflectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @author: e20160504
 * @date:  2018/7/16
 * @desc:  所有DAO都继承此抽象类
 * o:params  t:examples
 */

public abstract class BaseDao<T> implements IDao<T> {

    @Autowired
    private MyMapper<T> mapper;

    /**
    *@params: filters 继承 PageFilter
    *@return: 分页结果
    *@desc:   模糊查询
    */
    public Page<T> list(Object filters) {
        Class<Object> aClass = ReflectionUtil.getClassGenricType(this.getClass());
        Example example = getLikeExample(aClass, filters);
        Integer pageNo = (Integer)ReflectionUtil.getFieldValue(filters, "pageNo");
        Integer pageSize = (Integer)ReflectionUtil.getFieldValue(filters, "pageSize");
        PageHelper.offsetPage(pageNo,pageSize);
        Page<T> list = (Page<T>) mapper.selectByExample(example);
        return list;
    }

    /**
    *@params:  key
    *@return:
    *@desc: 通过主键进行删除,这里最多只会删除一条数据 单个字段做主键时,可以直接写主键的值 联合主键时,key可以是实体类,也可以是Map
    */
    public int deleteByPrimaryKey(Object o){
        return mapper.deleteByPrimaryKey(o);
    } ;

    /**
    *@params:
    *@return:
    *@desc: 根据实体属性作为条件进行删除，查询条件使用等号
    */
    public int delete(T t) {
        return mapper.delete(t);
    };

    /**
    *@params:
    *@return:
    *@desc: 保存一个实体，null的属性也会保存，不会使用数据库默认值
    */
    public int insert(T t) {
        return mapper.insert(t);
    };

    /**
    *@params:
    *@return:
    *@desc: 保存一个实体，null的属性不会保存，会使用数据库默认值
    */
    public int insertSelective(T t) {
        return mapper.insertSelective(t);
    };

    /**
    *@params:
    *@return:
    *@desc:
    */
    public boolean existsWithPrimaryKey(Object key) {
        return mapper.existsWithPrimaryKey(key);
    };

    /**
    *@params:
    *@return:
    *@desc: 查询全部结果，select(null)方法能达到同样的效果
    */
    public List<T> selectAll() {
        return mapper.selectAll();
    };

    /**
    *@params:
    *@return:
    *@desc: 根据主键字段进行查询，查询条件使用等号,单个主键字段可以直接查询，联合主键必须封装类或map
    */
    public T selectByPrimaryKey(Object key) {
        return mapper.selectByPrimaryKey(key);
    };

    /**
    *@params:
    *@return:
    *@desc: 据实体类不为null的字段查询总数,条件全部使用=号and条件
    */
    public int selectCount(T t) {
        return mapper.selectCount(t);
    };

    /**
    *@params:
    *@return:
    *@desc: 据实体类不为null的字段进行查询,条件全部使用=号and条件
    */
    public List<T> select(T t) {
        return mapper.select(t);
    };

    /**
    *@params:
    *@return:
    *@desc: 根据实体中的属性进行查询，只能有一个返回值，有多个结果是抛出异常，查询条件使用等号
    */
    public T selectOne(T t) {
        return mapper.selectOne(t);
    };

    /**
    *@params:
    *@return:
    *@desc: 据主键进行更新,这里最多只会更新一条数据 参数为实体类
    */
    public int updateByPrimaryKey(T t) {
        return mapper.updateByPrimaryKey(t);
    };

    /**
    *@params:
    *@return:
    *@desc: 根据主键进行更新 只会更新不是null的数据
    */
    public int updateByPrimaryKeySelective(T t) {
        return mapper.updateByPrimaryKeySelective(t);
    };

    /**
    *@params: example
    *@return:
    *@desc: 根据Example条件删除数据
    */
    public int deleteByExample(Object example) {
        return mapper.deleteByExample(example);
    };

    /**
    *@params:
    *@return:
    *@desc: 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
    */
    public List<T> selectByExample(Object o) {
        //Example  e = new Example(User.class);
        //e.selectProperties("id","username");
        return mapper.selectByExample(o);
    };

    /**
    *@params:
    *@return:
    *@desc: 根据Example条件进行查询总数
    */
    public int selectCountByExample(Object o) {
        return mapper.selectCountByExample(o);
    };

    /**
    *@params:
    *@return:
    *@desc:
    */
    public T selectOneByExample(Object o) {
        return mapper.selectOneByExample(o);
    };

    /**
    *@params:
    *@return:
    *@desc: 根据Example条件更新实体record包含的全部属性，null值会被更新
    */
    public int updateByExample(T record, Object example) {
        return mapper.updateByExample(record,example);
    };

    /**
     *@params:
     *@return:
     *@desc: 根据Example条件更新实体record包含的全部属性，null值不会被更新
     */
    public int updateByExampleSelective(T record, Object example) {
        return mapper.updateByExampleSelective(record,example);
    };

    /**
    *@params:
    *@return:
    *@desc: 批量插入，支持批量插入的数据库可以使用，例如MySQL,H2等，另外该接口限制实体包含id属性并且必须为自增列
    */
    public int insertList(List<T> list) {
        return mapper.insertList(list);
    };

    /**
    *@params:
    *@return:
    *@desc: 插入数据，限制为实体包含id属性并且必须为自增列，实体配置的主键策略无效
    */
    public int insertUseGeneratedKeys(T t) {
        return mapper.insertUseGeneratedKeys(t);
    };


    //构造模糊查询的 Example
    public Example getLikeExample(Class clzz, Object obj){
        Example example = new Example(clzz);
        Example.Criteria criteria = example.createCriteria();
        Class cls = obj.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            String fieldName = field.getName();
            Object value = ReflectionUtil.getFieldValue(obj, fieldName);
            if (value != null) {
                criteria.andLike(fieldName, "%" + String.valueOf(value) + "%");
            }
        }
        return example;
    }
}
